/**
 * Copyright (c) 2018-2023, NXOS Development Team
 * SPDX-License-Identifier: Apache-2.0
 * 
 * Contains: atomic for x86
 * 
 * Change Logs:
 * Date           Author            Notes
 * 2023-08-23     JasonHu           Init
 */

#include <nxos/atomic.h>

#define LOCK_PREFIX "lock "

void NX_AtomicSet(NX_Atomic *atomic, NX_AtomicValue value)
{
    atomic->value = value;
}

NX_AtomicValue NX_AtomicGet(NX_Atomic *atomic)
{
    return atomic->value;
}

void NX_AtomicAdd(NX_Atomic *atomic, NX_AtomicValue value)
{
    NX_CASM(LOCK_PREFIX "addl %1,%0"   
         : "+m" (atomic->value)   
         : "ir" (value));
}

void NX_AtomicSub(NX_Atomic *atomic, NX_AtomicValue value)
{
    NX_CASM(LOCK_PREFIX "subl %1,%0"   
         : "+m" (atomic->value)   
         : "ir" (value));
}

void NX_AtomicInc(NX_Atomic *atomic)
{
    NX_CASM(LOCK_PREFIX "incl %0"   
         : "+m" (atomic->value));
}

void NX_AtomicDec(NX_Atomic *atomic)
{
    NX_CASM(LOCK_PREFIX "decl %0"   
         : "+m" (atomic->value));   
}

void NX_AtomicSetMask(NX_Atomic *atomic, NX_AtomicValue mask)
{
    NX_CASM(LOCK_PREFIX "orl %0,%1"
        : : "r" (mask), "m" (*(&atomic->value)) : "memory");
}

void NX_AtomicClearMask(NX_Atomic *atomic, NX_AtomicValue mask)
{    
    NX_CASM(LOCK_PREFIX "andl %0,%1"
         : : "r" (~(mask)), "m" (*(&atomic->value)) : "memory");
}

NX_AtomicValue NX_AtomicSwap(NX_Atomic *atomic, NX_AtomicValue newValue)
{
    NX_CASM("xchgl %k0,%1"   
         : "=r" (newValue)
         : "m" (*(&atomic->value)), "0" (newValue)   
         : "memory");
    return newValue;
}

NX_AtomicValue NX_AtomicCAS(NX_Atomic *atomic, NX_AtomicValue old, NX_AtomicValue newValue)
{
    NX_AtomicValue prev;
    NX_CASM(LOCK_PREFIX "cmpxchgl %k1,%2"   
         : "=a"(prev)
         : "r"(newValue), "m"(*(&atomic->value)), "0"(old)   
         : "memory");
    return prev;
}
